<?php
/**
 * Created by xun at 2020/5/12
 */

namespace app\storage;


use app\base\ArrayHelper;
use app\base\BaseObject;

class MysqlPool extends BaseObject
{
    use Singleton;

    protected $min = 10;

    protected $max = 100;
    /** @var $channel \Swoole\Channel */
    protected $channel;

    private $chanLen = 0;

    private $connectionCount = 0;

    private $connections = [];

    protected $config;

    public function init()
    {
        parent::init(); // TODO: Change the autogenerated stub
        $this->config = Config::getConfig('extend.mysql');
        $this->channel = new \Swoole\Channel(Config::getConfig('extend.channel.size'));
        $this->initQueue();
    }

    /**
     * 生成连接
     */
    public function initQueue()
    {
        for ($i = 0; $i < $this->min; $i++) {
            $id = $this->createConnection();
            if ($i) {
                $this->channel->push($id);
                $this->chanLen++;
            }
        }
    }

    private function createConnection()
    {
        $mysqli = new \Mysqli(
            $this->config['host'],
            $this->config['user'],
            $this->config['password'],
            $this->config['db']
        );
        if ($mysqli->connect_errno) {
            echo $mysqli->connect_errno;
            return null;
        }
        $mysqli->set_charset("utf8");
        echo 'add ' . $mysqli->thread_id . ' into pool ' . PHP_EOL;
        $this->connections[$mysqli->thread_id] = $mysqli;
        $this->connectionCount++;
        echo '当前connectionCount: ' . $this->connectionCount . PHP_EOL;
        return $mysqli->thread_id;
    }

    /**
     * @return \Mysqli
     */
    public function getConnection()
    {
        if ($this->connectionCount >= $this->max) {
            $id = !$this->channel->pop();
            while ($id) {
                usleep(2000);
                $id = $this->channel->pop();
                $this->chanLen--;
            }
        } else {
            $id = $this->channel->pop();
            $this->chanLen--;
        }

        echo '获取thread id: ' . $id . PHP_EOL;

        if ($id == 0) {
            $id = $this->createConnection();
            return $this->connections[$id];
        } else {
            /** @var \Mysqli $mysqli */
            $mysqli = $this->connections[$id];
            if (!is_null($mysqli) && $mysqli->ping()) {
                echo 'mysqli还活着，拿去8' . PHP_EOL;
                return $mysqli;
            } else {
                echo 'mysqli死了...' . PHP_EOL;
                $mysqli->close();
                unset($this->connections[$id]);
                $this->connectionCount--;
                $id = $this->createConnection();
                $this->channel->push($id);
                $this->chanLen++;
                return $this->connections[$id];
            }
        }
    }

    /**
     * @param $connection \Mysqli
     */
    public function free($connection)
    {
        $this->channel->push($connection->thread_id);
        $this->chanLen++;
        echo 'free thread id: ' . $connection->thread_id . PHP_EOL;
    }

    public function clear()
    {
        foreach ($this->connections as $connection) {
            $connection->close();
        }
    }

    /**
     * 维持当前的连接数不断线，并且剔除断线的链接
     */
    public function keepAlive()
    {
        swoole_timer_tick(5000, function () {
            while ($this->chanLen > 0 && $next = $this->channel->pop()) {
                $db = $this->connections[$next];
                $r = $db->query("select 1");
                if ($r === false) {
                    return;
                }
                $this->channel->push($next);
            }
        });

        swoole_timer_tick(5000, function () {
            if ($this->chanLen > $this->max) {
                while ($this->max < $this->channel->count()) {
                    $next = $this->channel->shift();
                    $next->close();

                    echo "关闭连接..." . PHP_EOL;
                }
            }
        });
    }

}
